#Football Schedule GUI program

import re
import gdata.calendar.service
import atom
import sys
from PyQt4 import QtGui, QtCore
import icalendar
from datetime import datetime
from icalendar import UTC

# Level abbreviations and game fees
levels = {"Freshman":"Fr", "JV":"JV", "Varsity":"V", "8th Grade":"8", "Invalid":"Invalid"}
fees = {"Fr" : 42, "JV" : 42, "V" : 56, "8": 42, "Invalid": 0}

# Game object stores info about a single game
class Game:
    #set default values
    def __init__(self):
        self.calid = "N/A"
        self.date = "2000-01-01"
        self.time = "16:00"
        self.level = "Invalid"
        self.visitor = "???"
        self.home = "???"
        self.worked = False
        self.pay = ""
        self.tithing = False
        self.where = ""
        self.idgroup = "UNKNOWN"
        self.assignor = "???"
        self.gameid = ""
        self.officials = {"REF" : "", "UMP" : "", "HL" : "", "LJ" : "", "BJ" : ""}
        self.mismatch = ""
    
    # read a google event object into this object
    def fromEvent(self, event):
        # this RE matches yyyy-mm-ddThh:mm format in the start time; date is group 1, time is group 2
        m = re.match("(\d{4,4}-\d{2,2}-\d{2,2})T(\d{2,2}:\d{2,2})", event.when[0].start_time)
        self.event = event
        idstart = event.id.text.rindex("/") + 1
        self.calid = event.id.text[idstart:]
        self.date = m.group(1)
        self.time = m.group(2)
        
        # vvshatp is Visitor vs Home at Place.  Matches game level (1), then a dash, then finds visitor (2) vs home (3)
        # vath is Visitor at Home.  Matches game level (1), then a dash, then visitor (2) @ home (3)
        vvshatp = ".*?\((Fr|V|JV|8)\)\s*-\s*(.+?)\s*vs\s*(.+?)\s+@"
        vath = ".*?\((Fr|V|JV|8)\)\s*-\s*(.+)\s*@\s*(.+)"
    
        # first try to match on Visitor vs Home at Place
        m = re.match(vvshatp, event.title.text)
        if (m):
            self.level = m.group(1).strip()
            self.visitor = m.group(2).strip()
            self.home = m.group(3).strip()
        else:
            # try Visitor at Home
            m = re.match(vath, event.title.text)
            if (m):
                self.level = m.group(1).strip();
                self.visitor = m.group(2).strip()
                self.home = m.group(3).strip()
                
        for lev in levels:
            # get the full/long name of the level
            if levels[lev] == self.level:
                self.level = lev
                break
        
        # derive pay from level, get where value and the event content for game details
        self.desc = event.content.text
        self.pay = fees[levels[self.level.__str__()]]
        self.where = event.where[0].value_string
        if self.where is not None:
            self.where = self.where.strip()
        
        #d_vvsh is a line for visitor (1) vs home (2)
        #d_level is a line for the game level
        #d_assign is a line for the Assignor name (1)
        #d_gameid is a line for the ID Group (1), and the actual ID# (2)
        #d_official is a line for matching a position, with the official (1) separating them (ie, REF - Person Name)
        d_vvsh = "(.+?)\s*vs\s*(.+)"
        d_level = "(Freshman|JV|Varsity|8th Grade)"
        d_assign = "\(Assignor - (.+?)\)"
        d_gameid = "(.+?) ID - (.*)"
        d_official = "(REF|UMP|HL|LJ|BJ)\s*-\s*(.*)"
        
        desclines = self.desc.splitlines(0)
        #pares each line of the content
        for descline in desclines:
            # for simplicity, do matches here for each line type
            m1 = re.match(d_vvsh, descline)
            m2 = re.match(d_level, descline)
            m3 = re.match(d_assign, descline)
            m4 = re.match(d_gameid, descline)
            m5 = re.match(d_official, descline)
            if (m1):
                # Visitor vs Home line
                d_vis = m1.group(1).strip()
                d_home = m1.group(2).strip()
                if (d_vis != self.visitor):
                    self.mismatch = self.mismatch + "Visitor mismatch: " + self.visitor + " ... " + d_vis + "\n"
                if (d_home != self.home):
                    self.mismatch = self.mismatch + "Home mismatch: " + self.home + " ... " + d_home + "\n"
            elif (m2):
                # Level line
                if self.level != m2.group(1):
                    self.mismatch = self.mismatch + "Level mismatch: " + self.level + " ... " + m2.group(1) + "\n"
            elif (m3):
                # Assignor line
                self.assignor = m3.group(1).strip()
            elif (m4):
                # Game ID line (and group for which the ID applies)
                self.idgroup = m4.group(1).strip()
                self.gameid = m4.group(2).strip()
            elif (m5):
                # Official/Position line
                position = m5.group(1).strip()
                officialname = m5.group(2).strip()
                self.officials[position] = officialname     
                
    # get a short summary string of the game
    def str_short(self):
        return '%s %s (%2s) %s vs %s' % (self.date, self.time, levels[self.level.__str__()], self.visitor, self.home)
      
      
    # get a longer string form of the entire game details
    def str(self):
        basicinfo = self.str_short()
        assignor = 'Assignor: %s' % (self.assignor)
        idinfo = '%s ID: %s' % (self.idgroup, self.gameid)
        officials = 'REF: %s\nUMP: %s\n HL: %s\n' % (self.officials['REF'], self.officials['UMP'], self.officials['HL'])
        
        # only add LJ and BJ if it's a Varsity game
        if levels[self.level.__str__()] == 'V':
            officials += ' LJ: %s\n BJ: %s\n' % (self.officials['LJ'], self.officials['BJ'])
        
        return '%s\n%s\n%s\n%s' % (basicinfo, assignor, idinfo, officials)
    
    
    # Get the string to use for the title of the game in the calendar
    def getTitle(self):
        title = '(%s) - %s ' % (levels[self.level.__str__()], self.visitor)
        # Do visitor @ home if the location is the same as the home, otherwise do visitor vs home @ location
        if (self.home == self.where):
            title += '@ %s' % (self.home)
        else:
            title += 'vs %s @ %s' % (self.home, self.where)
        return title
    
    
    # Get the string to use for the event content field in the calendar
    def getContent(self):
        maincontent =  '%s vs %s\n%s\n(Assignor - %s)\n%s ID - %s\n\n' % (self.visitor, self.home, self.level, self.assignor, self.idgroup, self.gameid)
        offic = 'REF - %s\nUMP - %s\nHL - %s' % (self.officials['REF'], self.officials['UMP'], self.officials['HL'])
        
        # only add the LJ and BJ to the content if it's a Varsity game
        if levels[self.level.__str__()] == 'V':
            offic += '\nLJ - %s\nBJ - %s' % (self.officials['LJ'], self.officials['BJ'])
        
        return '%s%s' % (maincontent, offic)


# A dialog box for loggin in
class LoginDialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        self.setWindowTitle('Login To Your Calendar')
        
        # Build the fields and buttons
        self.username = QtGui.QLineEdit()
        self.username.setMinimumWidth(150)
        self.password = QtGui.QLineEdit()
        self.password.setEchoMode(QtGui.QLineEdit.Password)
        self.password.setMinimumWidth(150)
        okButton = QtGui.QPushButton('OK')
        cancelButton = QtGui.QPushButton('Cancel')
        
        # Add them to the dialog box
        main = QtGui.QGridLayout()
        main.addWidget(QtGui.QLabel('Username'), 0, 0)
        main.addWidget(self.username, 0, 1)
        main.addWidget(QtGui.QLabel('Password') , 1, 0)
        main.addWidget(self.password, 1, 1)
        main.addWidget(okButton, 2, 0)
        main.addWidget(cancelButton, 2, 1)
        
        # Set the layout and connect the buttons to the dialogs built-in methods
        self.setLayout(main)
        
        self.connect(okButton, QtCore.SIGNAL("clicked()"), self.accept)
        self.connect(cancelButton, QtCore.SIGNAL("clicked()"), self.reject)


# A dialog for comfirming an export of the games list
class ExportDialog(QtGui.QDialog):
    def __init__(self):
        QtGui.QDialog.__init__(self)
        self.setWindowTitle('Export Schedule to iCalendar Format')

        # Build the fields and buttons
        self.filename = QtGui.QLineEdit()
        self.filename.setMinimumWidth(300)
        filebutton = QtGui.QPushButton("Browse...")
        self.onlyworkhours = QtGui.QCheckBox("Only export times during normal work hours")
        okButton = QtGui.QPushButton('OK')
        cancelButton = QtGui.QPushButton('Cancel')

        # Add them to the 
        main = QtGui.QGridLayout()
        main.addWidget(QtGui.QLabel('iCal File :'), 0, 0)
        main.addWidget(self.filename, 0, 1)
        main.addWidget(filebutton, 0, 2)
        main.addWidget(self.onlyworkhours, 1, 0, 1, 2)

        buttonLayout = QtGui.QHBoxLayout()
        buttonLayout.addStretch()
        buttonLayout.addWidget(okButton)
        buttonLayout.addSpacing(5)
        buttonLayout.addWidget(cancelButton)
        buttonLayout.addStretch()
        main.addLayout(buttonLayout, 2, 0, 1, 3)

        # Set the layout and connect the buttons to the dialogs methods
        self.setLayout(main)

        self.connect(okButton, QtCore.SIGNAL("clicked()"), self.accept)
        self.connect(cancelButton, QtCore.SIGNAL("clicked()"), self.reject)
        self.connect(filebutton, QtCore.SIGNAL("clicked()"), self.chooseFile)

    # open the filepicker and set the result in the dialog
    def chooseFile(self):
        filename = QtGui.QFileDialog.getSaveFileName(self, "Choose iCalendar File", "", "iCal Files (*.ics)")
        if filename != "":
            self.filename.setText(filename)
        

# A custom List Item for the game selection list, used to attach the actual game info to the item for retrieval
class GameListItem(QtGui.QListWidgetItem):
    def __init__(self,game):
        QtGui.QListWidgetItem.__init__(self, game.str_short())
        self.game = game

    
# A custom Date field, set to use the calendar popup and specified format.  Also supports the needed get and set fields
# so all info fields can be uniformly retrieved
class GameInfoDateEdit(QtGui.QDateEdit):
    def __init__(self,parent=None):
        QtGui.QDateEdit.__init__(self, parent)
        self.setCalendarPopup(True)
        self.setDisplayFormat("yyyy-MM-dd")
        self.setDate(QtCore.QDate.currentDate())
        
    def reset(self):
        self.setDate(QtCore.QDate.currentDate())    
        
    def setValue(self,newValue):
        self.setDate(QtCore.QDate.fromString(newValue, "yyyy-MM-dd")) 
        
    def getValue(self):
        return self.date().toString("yyyy-MM-dd")


# A custom Time field, set to use the specified format, and a default time (4PM).  
# Also supports the needed get and set fields so all info fields can be uniformly retrieved
class GameInfoTimeEdit(QtGui.QTimeEdit):    
    def __init__(self,parent=None):
        QtGui.QDateEdit.__init__(self, parent)
        self.setDisplayFormat("hh:mm")
        self.setTime(QtCore.QTime(16,00))
        
    def reset(self):
        self.setTime(QtCore.QTime(16,00))    
        
    def setValue(self, newValue):
        self.setTime(QtCore.QTime.fromString(newValue, "hh:mm"))
        
    def getValue(self):
        return self.time().toString("hh:mm")
    
        
# A custom single-line entry for most data, setting a disabled background and size constraints.
# Also contains custom get and set methods to be uniformly retrievable.
class GameInfoLineEdit(QtGui.QLineEdit):
    def __init__(self,parent=None):
        QtGui.QLineEdit.__init__(self, parent)
        self.palette().setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Background, QtGui.QColor(175,175,175))
        
        self.setMaximumHeight(30)
        self.setMinimumWidth(200)
        
    def reset(self):
        self.setText("")
        
    def setValue(self,newValue):
        self.setText(newValue)
        
    def getValue(self):
        return self.text()
    
    
# A custom combo box item, adding custom get and set methods to uniformly access values.
class GameInfoComboBox(QtGui.QComboBox):
    def __init__(self, valList, parent=None):
        QtGui.QComboBox.__init__(self,parent)
        self.addItems(valList)
        
    def reset(self):
        self.setCurrentIndex(0)    
        
    def setValue(self, newValue):
        i = self.findText(newValue)
        if i >= 0:
            self.setCurrentIndex(i)
        
    def getValue(self):
        return self.currentText()


# The Game Info widget is the right half of the dialog containing all the fields for a single game.
class GameInfoWidget(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        self.rowNum = 0
        
        self.resize(400,500)
        
        self.grid = QtGui.QGridLayout()
        
        # Add each input field; note that the field names match the field names in the Game object for easier conversion
        self.addInput('date', 'Date', GameInfoDateEdit())
        self.addInput('time', 'Time', GameInfoTimeEdit())
        self.addInput('level', 'Level', GameInfoComboBox(["Freshman", "JV", "Varsity", "8th Grade"]))
        self.addInput('visitor', 'Visitor', GameInfoLineEdit())
        self.addInput('home', 'Home', GameInfoLineEdit())
        self.addInput('where', 'Location', GameInfoLineEdit())
        self.addInput('assignor', "Assignor", GameInfoLineEdit())
        self.addInput('idgroup', 'ID Group', GameInfoLineEdit())
        self.addInput('gameid', 'Game ID', GameInfoLineEdit())
        self.addInput( 'REF', 'Referee', GameInfoLineEdit())
        self.addInput('UMP', 'Umpire', GameInfoLineEdit())
        self.addInput('HL', 'Head Linesman', GameInfoLineEdit())
        self.addInput('LJ', 'Line Judge', GameInfoLineEdit())
        self.addInput('BJ', 'Back Judge', GameInfoLineEdit())
        
        workpay = QtGui.QHBoxLayout()
        workpay.addWidget(QtGui.QCheckBox("Worked"))
        workpay.addWidget(QtGui.QLabel("Payment:"))
        workpay.addWidget(QtGui.QLineEdit())
        workpay.addWidget(QtGui.QCheckBox("Recorded"))
        
        self.grid.addLayout(workpay, self.rowNum,  0,  1,  4)
        
        # Connect the Level combo box to enable/disable the LJ/BJ fields depending on level chosen
        self.level.connect(self.level, QtCore.SIGNAL("currentIndexChanged(QString)"), self.updateLjBj)
        
        # Set the layout and enable/diable LJ/BJ based on current level value
        self.setLayout(self.grid)
        self.updateLjBj(self.level.getValue())
        
    # Add one input field to the widget, with it's label; add to the specified row of the grid.
    def addInput(self, varName, labelText, input):
        self.__dict__[varName] = input
        self.grid.addWidget(QtGui.QLabel(labelText + ":"),self.rowNum,0)
        self.grid.addWidget(input,self.rowNum,1)
        self.rowNum += 1
        
    # Enable the LJ/BJ fields for Varsity games, disable otherwise.
    def updateLjBj(self, newlevel):
        disable = True
        if newlevel == 'Varsity':
            disable = False
            
        self.LJ.setDisabled(disable)
        self.BJ.setDisabled(disable)
        
        if disable:
            self.LJ.setValue("N/A")
            self.BJ.setValue("N/A")
        else:
            if (self.LJ.getValue() == "N/A"):
                self.LJ.reset()
            if (self.BJ.getValue() == "N/A"):
                self.BJ.reset()
                

# The Main application window
class MainWindow(QtGui.QWidget):
    def __init__(self, parent=None):
        QtGui.QWidget.__init__(self, parent)
        
        self.setWindowTitle('Football Editor')
        
        # Add the list of games to the left, the game info widget on the right, with new game and save buttons
        leftvbox = QtGui.QVBoxLayout()
        self.gamelist = QtGui.QListWidget(self)
        self.gamelist.setMinimumWidth(400)
        self.gamelist.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        leftvbox.addWidget(self.gamelist)
        
        totalpayrow = QtGui.QHBoxLayout()
        totalpayrow.addWidget(QtGui.QLabel("Total Expected Pay :"))
        self.paylabel = QtGui.QLabel("$0")
        totalpayrow.addWidget(self.paylabel)
        leftvbox.addLayout(totalpayrow)

        newgamebutton = QtGui.QPushButton("New Game")
        leftvbox.addWidget(newgamebutton)
        exportbutton = QtGui.QPushButton("Export To iCal")
        leftvbox.addWidget(exportbutton)

        rightvbox = QtGui.QVBoxLayout()
        self.gameinfo = GameInfoWidget(self)
        rightvbox.addWidget(self.gameinfo)
        self.savebutton = QtGui.QPushButton("Save Game")
        rightvbox.addWidget(self.savebutton)
        
        hbox = QtGui.QHBoxLayout()
        hbox.addStretch(1)
        hbox.addLayout(leftvbox)
        hbox.addStretch(5)
        hbox.addLayout(rightvbox)
        hbox.addStretch(1)
      
        # Connect the game list to update the game info widget, and the new and save buttons to their methods
        self.gamelist.connect(self.gamelist, QtCore.SIGNAL('itemClicked(QListWidgetItem *)'), self.updateGame)
        newgamebutton.connect(newgamebutton, QtCore.SIGNAL('clicked()'), self.newGame)
        self.savebutton.connect(self.savebutton, QtCore.SIGNAL('clicked()'), self.saveGame)
        exportbutton.connect(exportbutton, QtCore.SIGNAL('clicked()'), self.exportIcal)
        
        self.setLayout(hbox)
        
    # Set the client so that the window can refresh itself
    def setClient(self, client):
        self.client = client
        
    # clear the game list and refresh it from the google calendar
    def refreshlist(self):
        self.gamelist.clear()
        
        # set up the query
        query = gdata.calendar.service.CalendarEventQuery('default', 'private', 'full')
        query.start_min = '2010-06-01'
        query.orderby = 'starttime'
        query.sortorder = 'a'
        query.max_results = 100

        # run the query into feed
        games = []
        feed = self.client.CalendarQuery(query)

        # initialize total pay
        totalpay = 0
        
        # Go through each event and add the game
        for i, event in enumerate(feed.entry):
            # This expression just checks to make sure it's a football game and not some other event in the calendar
            # Checks to see if it has (Fr), (JV) or (V) in the title
            m = re.match(".*?\((Fr|JV|V|8)\)", event.title.text)
            if (m):
                # If it matches, parse the game and add it to the list
                g = Game()
                g.fromEvent(event)
                games.append(g)    
                # get the abbreviation of the level, and then get the fee for that level
                totalpay += fees[levels[g.level]]

        # update the pay label text to be the total estimated pay
        self.paylabel.setText("$%d" % totalpay)
        
        # Go through each game and add it to the form list
        for game in games:
            self.gamelist.addItem(GameListItem(game))
            
        # clear the game info widget
        self.updateGame(None)
            
       
    # Update the game info widget based on the current game
    def updateGame(self, curr):
        if curr is not None:
            # If a game is selected, go through each of the games fields 
            for field in curr.game.__dict__:
                # If the fields is officials, go through each official and set the appropriate field value
                if field == 'officials':
                    for official in curr.game.officials:
                        if hasattr(self.gameinfo, official) and hasattr(getattr(self.gameinfo, official), "setValue"):
                            getattr(self.gameinfo, official).setValue(curr.game.officials[official])
                else:
                    # If it's not an official, set the appropriate field value if needed
                    if hasattr(self.gameinfo, field) and hasattr(getattr(self.gameinfo, field), "setValue"):
                        getattr(self.gameinfo, field).setValue(getattr(curr.game, field))  
        else:
            # If no game selected, just clear the widget
            self.clearInfo()
            
        # Enable/Disable LJ/BJ field as needed
        self.gameinfo.updateLjBj(self.gameinfo.level.getValue())
            
            
    # newgame just clears the info widget and deselects any selected game in the list
    def newGame(self):
        for item in self.gamelist.selectedItems():
            item.setSelected(False)        
        self.clearInfo()
            
    
    # Clear the game info widget
    def clearInfo(self):
        for field in self.gameinfo.__dict__:
            if hasattr(getattr(self.gameinfo, field), "reset"):
                getattr(self.gameinfo, field).reset()
                
    
    # save the current game to the calendar
    def saveGame(self):
        items = self.gamelist.selectedItems()
        game = Game()
        # disable the save button while running
        self.savebutton.setDisabled(True)
        
        # go through each field in the info widget
        for field in self.gameinfo.__dict__:
            # If a matching attribute in a game object is found, set the value, checking officials if needed
            if hasattr(game, field):
                setattr(game, field, getattr(self.gameinfo, field).getValue().__str__())
            elif field in game.officials:
                game.officials[field] = getattr(self.gameinfo, field).getValue().__str__()
            
        # If no location specified, just use the home team.
        if game.where == "":
            game.where = game.home    
        
        event = None    
        # If no game is selected, create a new entry, otherwise, use the existing entry in the game's object
        if len(items) == 0:
            event = gdata.calendar.CalendarEventEntry()
        else:
            event = items[0].game.event    
            # clear the when and where fields
            del event.when[0:len(event.when)]
            del event.where[0:len(event.where)]
            
        # set the event title, content, and where
        event.title = atom.Title(text=game.getTitle())
        event.content = atom.Content(text=game.getContent())
        event.where.append(gdata.calendar.Where(value_string=game.where))
        # build the start time info in UTC format
        start_time = '%sT%s:00.000' % (game.date, game.time)
        # If subvarsity, 2 hours for the game; Varsity is 4 hours
        gamelen = 2
        if (game.level == 'V'):
            gamelen = 4
        
        # set the stop time in UTC format based on the game length
        stop = QtCore.QTime(QtCore.QTime.fromString(game.time,"hh:mm")).addSecs(gamelen*60*60)
        stop_time = '%sT%s:00.000' % (game.date, stop.toString("hh:mm"))
        event.when.append(gdata.calendar.When(start_time=start_time, end_time=stop_time))
        
        try:
            boxtext = ""
            if len(items) == 0:
                # if a new game, use the insert event method
                self.client.InsertEvent(event, '/calendar/feeds/default/private/full')
                boxtext = "The game has been added to your calendar."
            else:
                # if updating a previous game, use the update event method
                # note that you must get the edit link from the object in order to do the update
                self.client.UpdateEvent(event.GetEditLink().href, event)
                boxtext = "The game has been modified."
            
            # refresh the list and display the message
            self.refreshlist()
            msgBox = QtGui.QMessageBox()
            msgBox.setText(boxtext)
            msgBox.exec_()
        except gdata.service.RequestError as err:
            # if there was a problem with the save, display the error message
            msgBox = QtGui.QMessageBox()
            msgBox.setText("ERROR: " + str(err))
            msgBox.exec_()
        
        # re-enable the save button
        self.savebutton.setDisabled(False)


    # export the current game list to an iCalendar file
    def exportIcal(self):
        # open the confirm dialog
        confirmDialog = ExportDialog()
        if confirmDialog.exec_() == QtGui.QDialog.Rejected:
            return

        # get the values from the dialog
        filename = confirmDialog.filename.text()
        onlywork = confirmDialog.onlyworkhours.isChecked()

        # create and initialize the Calendar object
        cal = icalendar.Calendar()
        cal.add('prodid', '-//Football Calendar//gmail.com//')
        cal.add('version', '2.0')
        
        # go through each game in the list
        numgames = self.gamelist.count()
        for i in range(0, numgames):
            # get the Game object and date/time info
            game = self.gamelist.item(i).game
            (year, month, day) = game.date.split("-")
            year = int(year)
            month = int(month)
            day = int(day)
            (hour, minute) = game.time.split(":")
            hour = int(hour)
            minute = int(minute)

            # Give an hour and a half "travel time"
            if minute < 30:
                hour -= 2
                minute += 30
            else:
                hour -= 1
                minute -= 30

            # create the datetime objects
            start = datetime(year, month, day, hour, minute, 0)
            stop = datetime(year, month, day, hour+4, minute, 0)

            # if a weekend game or past 5:00PM, and only games during work
            # time are wanted, skip this game
            if onlywork and (start.weekday() >= 5 or hour >= 17):
                continue

            # create the generic game event (details aren't needed) and add it to the calendar
            event = icalendar.Event()
            event.add('summary', 'Football Game')
            event.add('dtstart', start) 
            event.add('dtend', stop) 
            event.add('dtstamp', datetime.now())
            event.add('priority', 3)
            event['uid'] = "%4d%02d%02dT%02d%02d00/sigmazero13@gmail.com" % (year, month, day, hour, minute)
            cal.add_component(event)

        # write the calendar file
        f = open(filename, 'wb')
        f.write(cal.as_string())
        f.close



# MAIN PROGRAM START

# create the application and main window objects
app = QtGui.QApplication(sys.argv)
main = MainWindow()

# display the login dialog.  If canceled, just quit.
loginDialog = LoginDialog()
if loginDialog.exec_() == QtGui.QDialog.Rejected:
    sys.exit()
    
client = gdata.calendar.service.CalendarService()
try:
    # Try to log into the service
    client.ClientLogin(loginDialog.username.text(),  loginDialog.password.text())
except gdata.service.Error as err:
    # if there's an error, display a message and quit
    msgBox = QtGui.QMessageBox()
    msgBox.setText("ERROR: " + str(err))
    msgBox.exec_()
    sys.exit()

# set the client, refresh the list, show the main window and run the application's event loop
main.setClient(client)
main.refreshlist()
main.show()
sys.exit(app.exec_())
